/*
 * fileoper.c
 *
 *  Created on: Jan 14, 2014
 *      Author: jqc
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#include "config.h"
#include "fileoper.h"
#include "returnval.h"

#define DEBUG	(DEBUG_SWITCH && 1)

int lockFile(char *fpath, FILE **fp)
{
	if (DEBUG)
		fprintf(stderr, "[%s] fpath=%s\n", __func__, fpath);

	if (NULL == (*fp = fopen(fpath, "a+")))
		return OPER_EFILE;

	if (-1 == lockf((*fp)->_fileno, F_LOCK, 0)) {
		fprintf(stderr, "[%s] lockf %s", __func__, strerror(errno));
		fclose(*fp);
		return OPER_EFILE;
	}

	return 0;
}

int unlockFile(FILE *fp)
{
	if (-1 == lockf(fp->_fileno, F_ULOCK, 0)) {
		fprintf(stderr, "[%s] lockf %s", __func__, strerror(errno));
		fclose(fp);
		return OPER_EFILE;
	}

	fclose(fp);
	return 0;
}

NODE *loadConfFile(FILE *fp)
{
	NODE *head = NULL;
	NODE *tail = NULL;
	NODE *newnode = NULL;
	char *p = NULL;
	char buf[LEN_CTNT_MAX] =
	{ '\0' };

	if (NULL == (head = (NODE *) malloc(sizeof(NODE)))) {
		fprintf(stderr, "[%s] malloc failed when loading\n", __func__);
		return NULL;
	}
	memset(head, 0, sizeof(NODE));
	head->next = NULL;
	tail = head;

	while (NULL != tail->next)
		tail = tail->next;

	fseek(fp, 0, SEEK_SET);
	while (NULL != fgets(buf, LEN_CTNT_MAX, fp)) {
		if (DEBUG)
			fprintf(stderr, "[%s] buf = %s\n", __func__, buf);

		if (NULL == (newnode = (NODE *) malloc(sizeof(NODE)))) {
			fprintf(stderr, "[%s] malloc failed when loading\n", __func__);
			free(head);
			head = NULL;
			return NULL;
		}
		memset(newnode, 0, sizeof(NODE));

		if ('#' == *buf || NULL == (p = strstr(buf, "="))) {
			// type annotation or empty line
			newnode->data.type = TLINE_NCONF;
			strncpy(newnode->data.ctnt.notConf, buf, LEN_CTNT_MAX);
		} else {
			// config line
			newnode->data.type = TLINE_CONF;
			if (1 < strlen(p)) {
				if ('\n' == *(p + strlen(p + 1)))
					*(p + strlen(p + 1)) = '\0';
				strncpy(newnode->data.ctnt.conf.val, p + 1, LEN_VAL_MAX);
			}
			*p = '\0';
			strncpy(newnode->data.ctnt.conf.key, buf, LEN_KEY_MAX);
		}

		// tail insert
		newnode->next = tail->next;
		tail->next = newnode;
		tail = newnode;
	}

	return head;
}

int writeConfFile(FILE *fp, NODE *confmap)
{
	NODE *iter = confmap->next;

	if (-1 == ftruncate(fp->_fileno, 0)) {
		fprintf(stderr, "[%s] ftruncate %s\n", __func__, strerror(errno));
		return OPER_EFILE;
	}

	fseek(fp, 0, SEEK_SET);
	while (NULL != iter) {
		if (TLINE_CONF == iter->data.type) {
			if (0 > fprintf(fp, "%s=%s\n", iter->data.ctnt.conf.key, iter->data.ctnt.conf.val)) {
				fprintf(stderr, "[%s] fprintf %s\n", __func__, strerror(errno));
				return OPER_EFILE;
			}
		} else
			fputs(iter->data.ctnt.notConf, fp);

		iter = iter->next;
	}

	fflush(fp);
	return 0;
}
